home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Diamond Collection / The Diamond Collection (Software Vault)(Digital Impact).ISO / cdr44 / 2m30src.zip / 2MF.C < prev    next >
C/C++ Source or Header  |  1995-03-06  |  50KB  |  1,386 lines

  1.  
  2. /*───────────────────────────────────────────────────────────────────\
  3. │                                                                    │
  4. │                         █████ █   █ █▀▀▀▀                          │
  5. │                             █ ██ ██ █                              │
  6. │                         █████ █ █ █ █▀▀                            │
  7. │                         █     █   █ █                              │
  8. │                         █████ █   █ █                              │
  9. │                                                                    │
  10. │        2MF.C  3.0  -  UTILIDAD DE FORMATEO DE DISQUETES 2M         │
  11. │                                                                    │
  12. │               (C) 1993-1995 Ciriaco García de Celis.               │
  13. │                                                                    │
  14. │   - Para cualquier Turbo C o Borland C en modelo de memoria LARGE. │
  15. │   - Este programa se compila abriendo un proyecto e introduciendo  │
  16. │     en él 2MF.C y 2MFKIT.OBJ                                       │
  17. │   - Importante: no activar ciertas optimizaciones que no lo están  │
  18. │     por defecto (como la de alineamiento a palabra o la de salto). │
  19. │                                                                    │
  20. │   - NOTA: Las funciones de bajo nivel que acceden directamente a   │
  21. │           la controladora de disquetes no son indispensables, tan  │
  22. │           sólo se emplean para producir menos ruido al detectar    │
  23. │           la introducción de un nuevo disquete en la unidad.       │
  24. │                                                                    │
  25. │           Este programa detecta además la presencia de una posible │
  26. │           utilidad de intercambio de unidades A:-B: llamada FDSWAP │
  27. │           para que en caso de estar activado dicho intercambio sea │
  28. │           posible acceder a la unidad física correspondiente.      │
  29. │                                                                    │
  30. \───────────────────────────────────────────────────────────────────*/
  31.  
  32.  
  33. #include <stdlib.h>
  34. #include <stdio.h>
  35. #include <string.h>
  36. #include <dos.h>
  37. #include <bios.h>
  38. #include <time.h>
  39. #include <alloc.h>
  40. #include <conio.h>
  41. #include <io.h>
  42. #include <fcntl.h>
  43.  
  44.  
  45. #define CARDWARE    100   /* nº discos formateados antes del aviso */
  46. #define MAXSECT      46   /* máximo número de sectores por pista */
  47. #define MAXFAT     6128   /* mayor FAT de 12 bits posible */
  48. #define BOOT2M       80   /* bytes principales del Boot */
  49. #define FD_DATA   0x3F5   /* registro de datos del 765 */
  50. #define FD_STATUS 0x3F4   /* registro principal de estado del 765 */
  51. #define FD_DOR    0x3F2   /* registro de salida digital */
  52. #define FD_DIR    0x3F7   /* registro de entrada digital (RD) */
  53. #define FD_DCR    0x3F7   /* registro de control del disquete (WR) */
  54.  
  55.  
  56. typedef struct {                    /* sector arranque disquetes 2M */
  57.   unsigned char Salto[3], IdSis[8];
  58.   short    BytesSect;
  59.   char     SectCluster;
  60.   short    SectReserv;
  61.   char     NumFats;
  62.   short    FichRaiz, NumSect;
  63.   char     MediaId;
  64.   short    SectFat, SectPista, Caras;
  65.   long     Especiales, Sect32;
  66.   char     Unidad, Reservado, Flag;
  67.   long     NumSerie;
  68.   char     Titulo[11], TipoFat[8];
  69.   char     Flags;
  70.   char     CheckSum;
  71.   char     VersionFmt, FlagWr, VelPista0, VelPistaX;
  72.   short    OffsetJmp, OffsetPista0, OffsetPistaX, OffsetListaTam;
  73.   unsigned short FechaF;
  74.   unsigned short HoraF;
  75.   char     Resto[512-BOOT2M];  /* depende del tamaño de lo anterior */
  76.   } Boot;
  77.  
  78. typedef struct {                 /* entrada de directorio */
  79.   char Etiqueta[11];
  80.   char Tipo;
  81.   char Reservado[10];
  82.   int  Hora;
  83.   int  Fecha;
  84.   char Resto[6];
  85.   } Root;
  86.  
  87. typedef struct {                 /* parámetros en línea de comandos */
  88.   int   Unidad, UnidadLogica,
  89.         HD, ED, TipoFmt,
  90.         NoVerify, MarcaPoco,
  91.         Pistas, FichRaiz, Silencioso, NoPausa, NoTecla, X, Y, G,
  92.         Tipoetiq, NoFlash, Rapido;
  93.   char  Volumen[12];
  94.   } Parametros;
  95.  
  96.  
  97. int    HablaSp (void),
  98.        Hay2m (void),
  99.        Hay2mBoot (void),
  100.        FdswapOn (void),
  101.        TipoDrive (int),
  102.        EsperarCambioDisco (int, int),
  103.        infdc (void),
  104.        ValeDensidad (Boot *, Parametros *),
  105.        FormatearDisco (Boot *,unsigned char far *,unsigned char far *,
  106.                        Parametros *, long *, int *),
  107.        MarcaFat (int, int, Boot *, int, int, unsigned char far *,
  108.                  unsigned char far *, long *),
  109.        InicializaDisco (int, Boot *, unsigned char far *,
  110.                         unsigned char far *);
  111. void   Ayuda (void),
  112.        ProcesarParametros (int, char **, Parametros *),
  113.        DetectaMedio (Parametros *, Boot *),
  114.        CrearSector0 (Boot *, Parametros),
  115.        DiagnosticoError (int),
  116.        InformeDisco (Boot *, Parametros *, long, int),
  117.        IncrementarEtiqueta (Parametros *),
  118.        SonidoSube (void),
  119.        SonidoBaja (void),
  120.        SonidoError (void),
  121.        SonidoOn (void),
  122.        SonidoOff (void),
  123.        Sonido (int),
  124.        posicionar (int, int),
  125.        outfdc (unsigned char),
  126.        EsperarInt (void),
  127.        CardWare (char *, int);
  128. extern BootHDPrg, BootHDPrgLong, BootDDPrg, BootDDPrgLong,
  129.        Boot2mCode, Boot2mLong,
  130.        biosdsk (int, int, int, int, int, int, void far *);
  131.        void interrupt NuevaInt24 (void);
  132. extern void PicoRetardo (void), interrupt (*ViejaInt24) (void);
  133.  
  134.  
  135.  
  136. int      sp;                  /* 1-español 0-inglés */
  137.  
  138. unsigned long far *cbios=MK_FP(0x40, 0x6C);  /* reloj del sistema */
  139. unsigned char far *irq6=MK_FP(0x40, 0x3E);   /* flag BIOS de IRQ6 */
  140.  
  141.  
  142. void main (int argc, char **argv)
  143. {
  144.   Boot       sector0;
  145.   Parametros cmd;
  146.   int        salir, result, sg, detectar, tec;
  147.   long       bytes_err, dir;
  148.   unsigned   char far *buffer;    /* para contener toda una pista */
  149.   unsigned   char far *fat;       /* para contener toda la FAT */
  150.   int        disquetes=0;         /* nº discos formateados */
  151.   void interrupt
  152.     (*ViejaInt24) (void);
  153.  
  154.   sp=HablaSp();  /* determinar idioma del país */
  155.  
  156.   ProcesarParametros (argc, argv, &cmd);
  157.  
  158.   if (!Hay2m())
  159.       if (!Hay2mBoot()) {
  160.         if (sp)
  161.             printf("  2M ó 2MX 3.0 no está instalado, imposible formatear.\n");
  162.           else
  163.             printf("  2M or 2MX 3.0 is not installed, impossible to format.\n");
  164.         exit(128);
  165.         }
  166.       else {
  167.         if (sp)
  168.             printf("  Modo SuperBOOT: instale 2M para dar formato.\n");
  169.           else
  170.             printf("  SuperBOOT mode: needed to install 2M to format.\n");
  171.         exit(127);
  172.         }
  173.  
  174.   if (((fat=farmalloc( (unsigned long) MAXFAT))==NULL) ||
  175.       ((buffer=farmalloc( (unsigned long) MAXSECT<<10))==NULL)) {
  176.       if (sp) printf("  Memoria insuficiente.\n");
  177.         else printf("  Insufficient memory.\n");
  178.       exit(126);
  179.       }
  180.  
  181.   /* Definir el buffer para que no cruce una frontera de DMA */
  182.  
  183.   dir = ((unsigned long) FP_SEG(buffer) <<4) + FP_OFF(buffer);
  184.   if ((dir >> 16) != ((dir + ((unsigned long) MAXSECT << 9)) >> 16))
  185.     buffer+=(unsigned long) MAXSECT << 9;
  186.  
  187.   if (!cmd.NoPausa) {
  188.       if (sp)
  189.           printf("  Pulsa INTRO para formatear en");
  190.         else
  191.           printf("  Press ENTER to format on");
  192.       printf(" %c:", cmd.UnidadLogica+'A');
  193.       tec=getch(); if (!tec) tec=getch()<<8;
  194.       salir = (tec!=13);
  195.       }
  196.     else
  197.       salir=0;
  198.  
  199.   /* si no se indica densidad detectarla */
  200.  
  201.   detectar = (cmd.HD==-1);
  202.  
  203.   /* formateo de múltiples disquetes */
  204.  
  205.   while (!salir) {
  206.     if (detectar) DetectaMedio (&cmd, §or0);
  207.     CrearSector0 (§or0, cmd);
  208.     if (!cmd.Silencioso) SonidoSube();
  209.     switch (result=FormatearDisco (§or0, fat, buffer, &cmd,
  210.                                    &bytes_err, &sg)) {
  211.       case 0:  InformeDisco (§or0, &cmd, bytes_err, sg);
  212.                if (!cmd.Silencioso) SonidoBaja();
  213.                if (cmd.Tipoetiq==2) IncrementarEtiqueta (&cmd);
  214.                disquetes++;
  215.                break;
  216.       case 1:  DiagnosticoError (result);
  217.                break;
  218.       default: DiagnosticoError (result);
  219.                if (!cmd.Silencioso) SonidoError(); break;
  220.       }
  221.     if (cmd.NoTecla)
  222.         salir=1;
  223.       else {
  224.         if (sp)
  225.             printf("\n  Introduce otro disquete para formatear en");
  226.           else
  227.             printf("\n  Please insert another disk to format in");
  228.         printf(" %c:", cmd.UnidadLogica+'A');
  229.  
  230.         if (!EsperarCambioDisco(cmd.Unidad, cmd.NoFlash)) salir=1;
  231.         }
  232.     }
  233.   printf("\r                                                     \r");
  234.  
  235.   ViejaInt24=getvect(0x24);
  236.   setvect (0x24, NuevaInt24);      /* evitar error crítico */
  237.   CardWare (argv[0], disquetes);   /* intentar actualizar 2MF.EXE */
  238.   setvect (0x24, ViejaInt24);
  239. }
  240.  
  241.  
  242. void ProcesarParametros (int argc, char **argv, Parametros *cmd)
  243. {
  244.   unsigned char drv[128];
  245.   int           pm, error=0, hlp=0, id=1, disco;
  246.   union         REGS r;
  247.   struct        SREGS s;
  248.  
  249.   cmd->Unidad=cmd->TipoFmt=cmd->ED=cmd->NoVerify=cmd->MarcaPoco=\
  250.               cmd->FichRaiz=cmd->Silencioso=cmd->NoFlash=\
  251.               cmd->NoPausa=cmd->NoTecla=cmd->Tipoetiq=cmd->Rapido=0;
  252.   cmd->HD=-1; cmd->Pistas=82;
  253.   cmd->X=cmd->Y=cmd->G=-1;
  254.  
  255.   for (pm=1; pm<argc; pm++)
  256.     if (strstr(&argv[pm][1], "/")!=NULL) error=-1;  /* parámetros unidos */
  257.  
  258.   if (!error) {
  259.     for (pm=1; pm<argc; pm++) {
  260.       if ((strstr(argv[pm],"/L")!=NULL) || (strstr(argv[pm],"/l")!=NULL)) {
  261.         strncpy (cmd->Volumen, &argv[pm][3], 11);
  262.         cmd->Volumen[11]=0;
  263.         while (strlen(cmd->Volumen)<11) strcat(cmd->Volumen, " ");
  264.         cmd->Tipoetiq=1;
  265.         continue;
  266.         }
  267.       else if ((strstr(argv[pm],"/V")!=NULL) || (strstr(argv[pm],"/v")!=NULL)) {
  268.         strncpy (cmd->Volumen, &argv[pm][3], 11);
  269.         cmd->Volumen[11]=0;
  270.         while (strlen(cmd->Volumen)<11) strcat(cmd->Volumen, " ");
  271.         cmd->Tipoetiq=2;
  272.         continue;
  273.         }
  274.       strupr (argv[pm]);
  275.       if (strstr(argv[pm],"/?")!=NULL) hlp++;
  276.       else if ((strstr(argv[pm],"/H")!=NULL) && (strlen(argv[pm])==2)) hlp++;
  277.       else if (strstr(argv[pm],":")!=NULL)
  278.         for (disco='A'; disco <= 'Z'; disco++) {
  279.           drv[0]=disco; drv[1]=':'; drv[2]=0;
  280.           if ((strstr(argv[pm], drv)!=NULL) &&
  281.               (strstr(argv[pm], "/")==NULL)) cmd->Unidad=*argv[pm]-'A';
  282.           }
  283.       else if (strstr(argv[pm],"/HD")!=NULL) cmd->HD=1;
  284.       else if (strstr(argv[pm],"/DD")!=NULL) cmd->HD=0;
  285.       else if (strstr(argv[pm],"/D0")!=NULL) cmd->HD=2;
  286.       else if (strstr(argv[pm],"/D1")!=NULL) cmd->HD=3;
  287.       else if (strstr(argv[pm],"/F")!=NULL) cmd->TipoFmt=0;
  288.       else if (strstr(argv[pm],"/M")!=NULL) cmd->TipoFmt=1;
  289.       else if (strstr(argv[pm],"/ED")!=NULL) cmd->ED=1;
  290.       else if (strstr(argv[pm],"/N")!=NULL) cmd->NoVerify=1;
  291.       else if (strstr(argv[pm],"/W")!=NULL) cmd->MarcaPoco=1;
  292.       else if (strstr(argv[pm],"/T")!=NULL)
  293.         cmd->Pistas = atoi (&argv[pm][3]);
  294.       else if (strstr(argv[pm],"/R")!=NULL)
  295.         cmd->FichRaiz = atoi (&argv[pm][3]);
  296.       else if (strstr(argv[pm],"/S")!=NULL) { cmd->Silencioso=1; id++; }
  297.       else if (strstr(argv[pm],"/K")!=NULL) cmd->NoPausa=1;
  298.       else if (strstr(argv[pm],"/J")!=NULL) cmd->NoTecla=1;
  299.       else if (strstr(argv[pm],"/Z")!=NULL) cmd->NoFlash=1;
  300.       else if (strstr(argv[pm],"/X")!=NULL) cmd->X=atoi(&argv[pm][3]);
  301.       else if (strstr(argv[pm],"/Y")!=NULL) cmd->Y=atoi(&argv[pm][3]);
  302.       else if (strstr(argv[pm],"/G")!=NULL) cmd->G=atoi(&argv[pm][3]);
  303.       else if (strstr(argv[pm],"/I")!=NULL) { sp^=1; id++; }
  304.       else if (strstr(argv[pm],"/Q")!=NULL) cmd->Rapido++;
  305.       else error=1;
  306.       }
  307.     }
  308.  
  309.   cmd->UnidadLogica = cmd->Unidad;
  310.  
  311.   if (cmd->Unidad > 1) {
  312.     r.x.ax = 0x440D; r.x.bx = cmd->Unidad+1; r.x.cx = 0x860;
  313.     s.ds   = r.x.si = FP_SEG (drv);
  314.     r.x.dx = r.x.di = FP_OFF (drv); drv[0]=0;
  315.     intdosx (&r, &r, &s);
  316.     if ((!(r.x.flags & 1)) && (
  317.          (drv[6]=='2'+'M') || (drv[6]=='2'+'M'+1)
  318.          )
  319.        ) cmd->Unidad = drv[6] - ('2'+'M');  /* unidad 2MGUI */
  320.     }
  321.  
  322.   if (cmd->ED && (cmd->HD!=1)) cmd->HD=1;  /* /DD ó /Dx + /E = /E */
  323.  
  324.   if ((argc<=1) || (argc==id)) hlp++;
  325.  
  326.   if (hlp) Ayuda();
  327.  
  328.   if (sp)
  329.       printf("\n2MF 3.0 - Utilidad de formateo de disquetes 2M         (ESC Salir)\n");
  330.     else
  331.       printf("\n2MF 3.0 - Format utility program for 2M diskettes      (ESC Aborts)\n");
  332.   if (error==1) {
  333.     if (sp)
  334.         printf("  Error de sintaxis. Ejecute 2MF /?.\n");
  335.       else
  336.         printf("  Incorrect parameter(s). Execute 2MF /?.\n");
  337.     exit (2);
  338.     }
  339.   if (error==-1) {
  340.     if (sp)
  341.         printf("  Error: Los parámetros deben separarse por espacios.\n");
  342.       else
  343.         printf("  Error: Parameters must be separated by blank spaces.\n");
  344.     exit (2);
  345.     }
  346.   if (cmd->Unidad > 1) {
  347.     if (sp)
  348.         printf("    La unidad lógica indicada no es una disquetera.\n");
  349.       else
  350.         printf("    Logical drive indicated does not is a diskette drive.\n");
  351.     exit (2);
  352.     }
  353.   if (TipoDrive(cmd->Unidad)==0) {
  354.     if (sp)
  355.         printf("    La unidad física indicada no existe.\n");
  356.       else
  357.         printf("    Physical drive indicated does not exist.\n");
  358.     exit (2);
  359.     }
  360.   if ((TipoDrive(cmd->Unidad)!=2) && (TipoDrive(cmd->Unidad)<4)) {
  361.     if (sp)
  362.         printf("    La unidad indicada no es de alta densidad.\n");
  363.       else
  364.         printf("    Drive indicated it is not high density one.\n");
  365.     exit (2);
  366.     }
  367.   if ((TipoDrive(cmd->Unidad)<5) && (cmd->ED==1)) {
  368.     if (sp)
  369.         printf("    Necesaria unidad de 2.88M para formato ED.\n");
  370.       else
  371.         printf("    Needs a 2.88M drive to perform ED format.\n");
  372.     exit (2);
  373.     }
  374.   if ((cmd->Pistas<80) || (cmd->Pistas>86)) {
  375.     if (sp)
  376.         printf("  Error: Número de pistas incorrecto.\n");
  377.       else
  378.         printf("  Error: Incorrect number of tracks.\n");
  379.     exit (2);
  380.     }
  381.   if (cmd->FichRaiz && ((cmd->FichRaiz<1) || (cmd->FichRaiz>240))) {
  382.     if (sp)
  383.         printf("  Error: Nº de ficheros en directorio raiz erróneo.\n");
  384.       else
  385.         printf("  Error: Bad number of files in root directory.\n");
  386.     exit (2);
  387.     }
  388. }
  389.  
  390.  
  391. void Ayuda()
  392. {
  393.   if (sp) {
  394.       printf("\n\n"
  395.         "         2MF 3.0 - UTILIDAD ESTANDAR DE FORMATEO DE DISQUETES PARA 2M\n"
  396.         "   (C) 1993-1995 Ciriaco García de Celis - Grupo Universitario de Informática\n"
  397.         "   C/Renedo, 2, 4-C; 47005 Valladolid (España) - ciri@gui.uva.es - 2:341/21.8\n\n"
  398.         " 2MF U: [/HD|DD|ED] [/F|M] [/N] [/L|V=etiq] [/S] [/Z] [/R=nn] [/T=nn] [/K] [/J]\n\n"
  399.         "    Este programa formatea disquetes a una mayor capacidad y/o velocidad de la\n"
  400.         "  normal. Para que estos nuevos disquetes funcionen debe estar instalado 2M en\n"
  401.         "  memoria. Alternativamente, si son de alta densidad se pueden dejar dentro de\n"
  402.         "  la unidad A: y reinicializar el ordenador,  que botará pese a todo del disco\n"
  403.         "  duro y podrá acceder a los disquetes 2M sin problemas en lectura/escritura.\n\n"
  404.         "  /HD  Formateo en alta densidad (por defecto si 2MF no detecta la densidad).\n"
  405.         "  /DD  Fuerza el formateo en doble densidad (aunque 2MF quizá la detecte).\n"
  406.         "  /ED  Formatear disquetes de 3½-ED (3608K por defecto o 3772K indicando /M).\n"
  407.         "   /F  Disquetes rápidos y seguros -por defecto- (5¼:820-1476K, 3½:984-1804K).\n"
  408.         "   /M  Formatear disquetes a la máxima capacidad (5¼:902-1558K, 3½:1066-1886K).\n"
  409.         "   /N  No verificar el disquete destino (peligroso en modo /M).\n"
  410.         "   /L  Poner etiqueta de volúmen al disco destino (minúsculas permitidas).\n"
  411.         "   /V  Etiqueta incremental en series de discos (si termina en número).\n"
  412.         "   /S  Funcionamiento silencioso         /Z  Evitar parpadeo de LED de disco.\n"
  413.         "   /R  Elegir nº ficheros raíz (1-240)   /T  Cambiar número de pistas (80-86).\n"
  414.         "   /K  No realizar pausa inicial         /J  No realizar pausa final.\n");
  415.       }
  416.     else {
  417.       printf("\n\n"
  418.         "               2MF 3.0 - STANDARD FORMAT UTILITY FOR 2M DISKETTES\n"
  419.         "   (C) 1993-1995 Ciriaco García de Celis - Grupo Universitario de Informática\n"
  420.         "   C/Renedo, 2, 4-C; 47005 Valladolid (Spain)  - ciri@gui.uva.es - 2:341/21.8\n\n"
  421.         " 2MF U: [/HD|DD|ED] [/F|M] [/N] [/L|V=label] [/S][/Z] [/R=nn] [/T=nn] [/K][/J]\n\n"
  422.         "    This program formats diskettes at a higher capacity and/or speed than the\n"
  423.         "  normal ones.  2M must be installed on memory to provide support for the new\n"
  424.         "  diskettes.  Also, high-density diskettes can be left into A: drive and then\n"
  425.         "  computer can be rebooted: really it will boot from hard disk and after this\n"
  426.         "  moment 2M diskettes will be supported in the standard read-write operation.\n\n"
  427.         "  /HD  High density format (by default if 2MF can't detect diskette density).\n"
  428.         "  /DD  Request a double-density format (but 2MF perhaps can detect DD disk).\n"
  429.         "  /ED  Formats 3.5-ED diskettes at 3608K (or 3772K if /M option enabled).\n"
  430.         "   /F  Fast and reliable diskettes -by default- (5¼:820-1476K, 3½:984-1804K).\n"
  431.         "   /M  Formats diskettes up to maximum capacity (5¼:902-1558K, 3½:1066-1886K).\n"
  432.         "   /N  Do not verify target diskette (dangerous in /M mode).\n"
  433.         "   /L  Sets diskette volume label (case sensitive).\n"
  434.         "   /V  Automatic sequencing of labels (if specified one is number terminated).\n"
  435.         "   /S  Tells 2MF not to make sound effects  /Z  Turn disk LED «flashing» off.\n"
  436.         "   /R  Sets root entries number (1-240)     /T  Sets number of tracks (80-86).\n"
  437.         "   /K  No initial pause before formatting   /J  No end pause after formatting.\n");
  438.       }
  439.   exit (1);
  440. }
  441.  
  442.  
  443. int Hay2m()     /* devolver 1 si 2M está instalado */
  444. {
  445.   int entrada, instalado=0;
  446.   union REGS r; struct SREGS s;
  447.  
  448.   for (entrada=0xc0; (entrada<=0xff) && (!instalado); entrada++) {
  449.     r.x.ax=entrada << 8; s.es=0x1492; r.x.di=0x1992;
  450.     int86x (0x2f, &r, &r, &s);
  451.     if (r.x.ax==0xFFFF)
  452.       if ((peek(s.es,r.x.di-4)==9002) && (peek(s.es,r.x.di-2)==10787))
  453.         if (strstr (MK_FP(s.es, r.x.di),"2M:3.0")) instalado=1;
  454.         if (strstr (MK_FP(s.es, r.x.di),"2MX:3.0")) instalado=1;
  455.     }
  456.   return (instalado);
  457. }
  458.  
  459.  
  460. int Hay2mBoot()     /* devolver 1 si 2M instalado en modo SuperBOOT */
  461. {
  462.   return (strstr(MK_FP(((unsigned) peek(0x40, 0x13) * 64), 4),
  463.                  "2M-STV")!=NULL);
  464. }
  465.  
  466.  
  467. int FdswapOn() /* devolver 1 si FDSWAP 1.1+ está instalado y activo */
  468. {
  469.   int entrada, instalado=0;
  470.   union REGS r; struct SREGS s;
  471.  
  472.   for (entrada=0xc0; (entrada<=0xff) && (!instalado); entrada++) {
  473.     r.x.ax=entrada << 8; s.es=0x1492; r.x.di=0x1992;
  474.     int86x (0x2f, &r, &r, &s);
  475.     if (r.x.ax==0xFFFF)
  476.       if ((peek(s.es,r.x.di-4)==9002) && (peek(s.es,r.x.di-2)==10787))
  477.         if (strstr (MK_FP(s.es, r.x.di),":FDSWAP:")) instalado=1;
  478.     }
  479.   return ((instalado) && (peekb(s.es, peek(s.es,r.x.di-6)-1)==1));
  480. }
  481.  
  482.  
  483. void CrearSector0 (Boot *s0, Parametros cmd)
  484. {
  485.   unsigned tipo, tabla, i, j, k, m, t, s, tam, ini, fin, inc;
  486.   char     id[8]="2M-STV00", ch, sum, far *p;
  487.   struct   time h;
  488.   struct   date f;
  489.   static unsigned char infofis [2][3][2][4][20] =
  490.   {{{{{10,176,7,0,1,1},        {9,80,1,1},            /* 5¼-DD  /F */
  491.       {5,100,3,1,1}                             },
  492.      {{11,176,7,1,1,1},        {9,80,1,1},            /*        /M */
  493.       {32,4,5,3,1,4,2,0},      {4,2,4,3,0}      }},
  494.     {{{18,224,7,0,0,0},        {16,60,1,1},           /* 5¼-HD  /F */
  495.       {9,50,3,1,2}                              },
  496.      {{19,224,7,1,0,0},        {17,25,1,2},           /*        /M */
  497.       {53,3,6,4,1,5,2,6,3},    {4,4,2,4,4,3}    }},
  498.     {{{0,0,0,0,0,0},           {0,0,0,0},             /* no usado  */
  499.       {0,0,0,0,0},                              },
  500.      {{14,192,7,1,2,1},        {9,80,1,1},            /* 3½-DD /D1 */
  501.       {38,2,4,3,1,4,2},        {4,3,4,4}        }}},
  502.    {{{{12,192,7,0,2,1},        {9,80,1,1},            /* 3½-DD  /F */
  503.       {6,100,3,1,1}                             },
  504.      {{13,192,7,1,2,1},        {9,80,1,1},            /*        /M */
  505.       {38,5,6,3,1,4,2,0,0},    {4,2,4,4,0,0}    }},
  506.     {{{22,224,7,0,0,0},        {19,70,1,1},           /* 3½-HD  /F */
  507.       {11,40,3,1,2}                             },
  508.      {{23,224,7,1,0,0},        {19,70,1,1},           /*        /M */
  509.       {64,3,7,4,1,5,2,6,3,7},  {4,4,4,4,4,3,2}  }},
  510.     {{{44,240,7,0,3,3},        {36,108,1,1},          /* 3½-ED  /F */
  511.       {11,126,4,1,2}                            },
  512.      {{46,240,7,1,3,3},        {36,108,1,1},          /*        /M */
  513.       {127,5,12,1,7,2,8,3,9,4,10,5,11,6,12},
  514.       {4,4,4,4,4,4,4,4,4,4,4,3}                 }}}};
  515.  
  516.   /* Significado de la tabla /F:
  517.       {SectLogPistaX, fichraiz, verFmt, flagWr, velpista0, velpistaX},
  518.       {sectpista0, GAP3pista0, primsectpista0, interleavepista0},
  519.       {SectFisPistaX, GAP3pistaX, tamsectpistaX, /X, /Y}
  520.      Significado de la tabla /M:
  521.       {SectLogPistaX, fichraiz, verFmt, flagWr, velpista0, velpistaX},
  522.       {sectpista0, GAP3pista0, primsectpista0, interleavepista0},
  523.       {Sectpreformat, GAP3pistaX, SectFisPistaX, sects numerados...},
  524.       {tamaños de sectores por orden...}
  525.   */
  526.  
  527.   if ((cmd.HD==2) && (TipoDrive(cmd.Unidad)>=4)) {
  528.       cmd.HD=0; tabla=0; tipo=0;
  529.       infofis[0][0][cmd.TipoFmt][0][4]=2;    /* 3½-DD a 250 Kbps */
  530.       infofis[0][0][cmd.TipoFmt][0][5]=2;
  531.       }
  532.   else if ((cmd.HD==3) && (TipoDrive(cmd.Unidad)>=4)) {
  533.       cmd.HD=tipo=0;
  534.       cmd.TipoFmt=1; tabla=2;                /* 3½-DD con 1148K */
  535.       }
  536.     else {
  537.       if (cmd.HD>1) cmd.HD=0;
  538.       tabla=cmd.HD+cmd.ED;            /* seleccionar tabla de datos */
  539.       if (TipoDrive(cmd.Unidad)<3)
  540.           tipo=0;  /* 5¼ */
  541.         else
  542.           tipo=1;  /* 3½ */
  543.       }
  544.  
  545.   ch=1+cmd.HD;
  546.   if (TipoDrive(cmd.Unidad)>2) ch+=2; if (!cmd.TipoFmt) ch+=4;
  547.   if (cmd.ED) ch=10-cmd.TipoFmt;
  548.   id[6]=(ch/10)+'0'; id[7]=(ch % 10)+'0'; strncpy (s0->IdSis, id, 8);
  549.  
  550.   s0->BytesSect=512;
  551.   s0->SectCluster = s0->SectReserv = 1;  s0->NumFats=2;
  552.   if (cmd.ED) s0->SectCluster=2;
  553.  
  554.   if (!cmd.FichRaiz)
  555.       s0->FichRaiz=infofis[tipo][tabla][cmd.TipoFmt][0][1];
  556.     else
  557.       if (cmd.FichRaiz % 16)
  558.           s0->FichRaiz=((cmd.FichRaiz >> 4) + 1) << 4;
  559.         else
  560.           s0->FichRaiz=cmd.FichRaiz;
  561.  
  562.   if (ch==6)
  563.       s0->MediaId=0xF0;   /* compatible SCANDISK */
  564.     else
  565.       s0->MediaId=0xFA;   /* compatible SCANDISK */
  566.  
  567.   s0->SectPista=infofis[tipo][tabla][cmd.TipoFmt][0][0];
  568.   s0->Caras=2;
  569.   s0->NumSect=cmd.Pistas*s0->Caras*s0->SectPista;
  570.  
  571.   j = 3 * (s0->NumSect - (s0->FichRaiz>>4) - 1);
  572.   k = 6 + 1024 * s0->SectCluster;
  573.   s0->SectFat = j/k; if (j % k) s0->SectFat++;
  574.  
  575.   s0->Unidad = s0->Reservado = 0; s0->Especiales = s0->Sect32 = 0L;
  576.   s0->Flag=0x29; randomize();
  577.   for (i=0; i<4; i++)
  578.     s0->NumSerie = (s0->NumSerie<<8) | (unsigned char) random(32767);
  579.  
  580.   if (cmd.Tipoetiq)
  581.       strncpy (s0->Titulo, cmd.Volumen, 11);
  582.     else
  583.       strncpy (s0->Titulo, "NO NAME    ", 11);
  584.  
  585.   strncpy (s0->TipoFat, "FAT12   ", 8);
  586.  
  587.   s0->VersionFmt=infofis[tipo][tabla][cmd.TipoFmt][0][2];
  588.   s0->FlagWr=infofis[tipo][tabla][cmd.TipoFmt][0][3];
  589.   s0->VelPista0=infofis[tipo][tabla][cmd.TipoFmt][0][4];
  590.   s0->VelPistaX=infofis[tipo][tabla][cmd.TipoFmt][0][5];
  591.  
  592.   s0->Flags=1;  /* Fecha y hora de formateo almacenada */
  593.   gettime (&h); getdate (&f);
  594.   s0->FechaF=((f.da_year-1980)<<9) | (f.da_mon<<5) | f.da_day;
  595.   s0->HoraF=(h.ti_hour<<11) | (h.ti_min<<5) | (h.ti_sec>>1);
  596.  
  597.   tam=BOOT2M; /* lo que precede a la primera tabla */
  598.   s0->OffsetPista0=tam;
  599.   s0->Resto[0]=infofis[tipo][tabla][cmd.TipoFmt][1][0];
  600.   s0->Resto[1]=infofis[tipo][tabla][cmd.TipoFmt][1][1];
  601.   ch=infofis[tipo][tabla][cmd.TipoFmt][1][2];
  602.   inc=infofis[tipo][tabla][cmd.TipoFmt][1][3];
  603.   ini=tam+2; fin=ini+s0->Resto[0]; k=0;
  604.   for (i=j=0; j<s0->Resto[0]; j++) {
  605.     s0->Salto[ini+i]=ch++; if (ch>s0->Resto[0]) ch=1;
  606.     i+=inc; if (ini+i>=fin) i=++k;
  607.     }
  608.  
  609.   ini=fin; s0->OffsetPistaX=ini;
  610.   if (!s0->FlagWr) {
  611.       k=infofis[tipo][tabla][cmd.TipoFmt][2][0]; j=5;
  612.       for (i=0; i<j; i++)
  613.         s0->Salto[ini+i]=infofis[tipo][tabla][cmd.TipoFmt][2][i];
  614.       if (cmd.X!=-1) s0->Salto[ini+3]=cmd.X;
  615.       if (cmd.Y!=-1) s0->Salto[ini+4]=cmd.Y;
  616.       }
  617.     else {
  618.       k=infofis[tipo][tabla][cmd.TipoFmt][2][2]; j=(k+1)*3;
  619.       for (i=0; i<3; i++)
  620.         s0->Salto[ini+i]=infofis[tipo][tabla][cmd.TipoFmt][2][i];
  621.       m=129;
  622.       for (i=3; i<=k*3; i+=3) {
  623.         s0->Salto[ini+i]=m;
  624.         s=infofis[tipo][tabla][cmd.TipoFmt][2][i/3+2];
  625.         s0->Salto[ini+i+1]=s;
  626.         t=infofis[tipo][tabla][cmd.TipoFmt][3][s-1];
  627.         switch (t) {
  628.           case 0: m+=1;  break;   case 1: m+=2;  break;
  629.           case 2: m+=3;  break;   case 3: m+=6;  break;
  630.           case 4: m+=11; break;   case 5: m+=22; break;
  631.           }
  632.         s0->Salto[ini+i+2]=t;
  633.         }
  634.       }
  635.   if (cmd.G!=-1) s0->Salto[ini+1]=cmd.G;
  636.   fin=ini+j;
  637.  
  638.   ini=fin; s0->OffsetListaTam=ini;
  639.   if (!s0->FlagWr)
  640.       for (i=0; i<k; i++)
  641.         s0->Salto[ini+i]=infofis[tipo][tabla][cmd.TipoFmt][2][2];
  642.     else
  643.       for (i=0; i<k; i++)
  644.         s0->Salto[ini+i]=infofis[tipo][tabla][cmd.TipoFmt][3][i];
  645.   fin=ini+k;
  646.  
  647.   ini=fin; s0->OffsetJmp=ini;
  648.   s0->Salto[0]=0xE9;
  649.   s0->Salto[1]=(ini-3) % 256; s0->Salto[2]=(ini-3) >> 8;
  650.  
  651.   if (cmd.HD == 0) {
  652.       p=(char far *) &BootDDPrg; k=BootDDPrgLong; }
  653.     else {
  654.       p=(char far *) &BootHDPrg; k=BootHDPrgLong; }
  655.  
  656.   for (i=0; (i<k) && (ini+i<509); i++) s0->Salto[ini+i]=*p++;
  657.   fin=ini+i;
  658.  
  659.   for (i=fin; i<510; i++) s0->Salto[i]=0;
  660.   if (fin<497) strncpy (&s0->Salto[496], "Made in Spain", 13);
  661.   s0->Salto[509]=0; s0->Salto[510]=0x55; s0->Salto[511]=0xAA;
  662.  
  663.   for (sum=0, j=64; j<ini; j++) sum+=s0->Salto[j]; /* checksum */
  664.   s0->CheckSum=-sum;
  665. }
  666.  
  667.  
  668. void DetectaMedio (Parametros *cmd, Boot *sector0)
  669. {
  670.   int sg;
  671.  
  672.   if (sp)
  673.       printf("\r  Determinando densidad del disquete...               ");
  674.     else
  675.       printf("\r  Detecting diskette media density...               ");
  676.   printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
  677.  
  678.   /* simular cambio de disco para inicialización plena de 2M */
  679.  
  680.   biosdsk (5, cmd->Unidad, 0, 0, 0xFF, 0x7F, NULL);
  681.   biosdsk (2, cmd->Unidad, 0, 0, 1, 1, (unsigned char far *) sector0);
  682.  
  683.   for (sg=0; sg<2; sg++) {
  684.     if (TipoDrive(cmd->Unidad)==2) /* en 5¼ intento pacífico */ {
  685.       cmd->HD=1; sg=2;
  686.       sg=biosdsk (0, cmd->Unidad, 0, 0, 0, 0, NULL);
  687.       sg=biosdsk (2, cmd->Unidad, 0, 0, 1, 1, (void *) sector0);
  688.       if (sg==6) /* cambio de disco */
  689.         sg=biosdsk (2, cmd->Unidad, 0, 0, 1, 1, (void *) sector0);
  690.       if (sg) break;
  691.       if ((peekb (0x40, 0x8B) >> 6)!=0) cmd->HD=0; break;
  692.       }
  693.  
  694.     cmd->ED=0; cmd->HD=1;
  695.     if ((sg=ValeDensidad (sector0, cmd))==0) break;  /* vale HD */
  696.     if (kbhit()) if (getch()==27) break;
  697.     if ((sg==3) || (sg==6) || (sg==128)) break;      /* error */
  698.     cmd->HD=0;
  699.     if (!ValeDensidad (sector0, cmd)) break;         /* vale DD */
  700.     cmd->HD=1; if (kbhit()) if (getch()==27) break;
  701.     cmd->HD=2;
  702.     if (!ValeDensidad (sector0, cmd)) break;         /* vale D0 */
  703.     cmd->HD=1; if (kbhit()) if (getch()==27) break;
  704.     cmd->ED=1;
  705.     if (!ValeDensidad (sector0, cmd)) break;         /* vale ED */
  706.     cmd->HD=1; cmd->ED=0; if (kbhit()) if (getch()==27) break;
  707.     }
  708.  
  709.   if (kbhit()) getch();  /* posible código de 2 bytes */
  710. }
  711.  
  712.  
  713. int ValeDensidad (Boot *sector0, Parametros *cmd)
  714. {
  715.   CrearSector0 (sector0, *cmd);
  716.   biosdsk (0, cmd->Unidad, 0, 0, 0, 0, NULL);
  717.   biosdsk (5, cmd->Unidad, 0, 0, 0, 0x7F,
  718.            (unsigned char far *) sector0);
  719.   return (biosdsk (2, cmd->Unidad, 0, 0,
  720.                       cmd->HD==1?15:cmd->ED==1?36:9, 1,
  721.                       (unsigned char far *) sector0));
  722. }
  723.  
  724.  
  725. int FormatearDisco (sector0, fat, buffer, cmd, bytes_def, segundos)
  726. Boot     *sector0;
  727. unsigned char far *fat;
  728. unsigned char far *buffer;
  729. Parametros *cmd;
  730. long     *bytes_def;
  731. int      *segundos;
  732. {
  733.   unsigned long dir, tiempo, rest, tini, hist[86], i, fase, fases;
  734.   int      cilindros, cilindro, cabezal, intento, error=1, spista, t;
  735.  
  736.   if (cmd->Rapido)
  737.     if (sp)
  738.         printf("\r  AVISO: ¡El formateo rápido no verifica!\n");
  739.       else
  740.         printf("\r  WARNING: Quick Format does not verifies!\n");
  741.  
  742.   if (cmd->G!=-1)
  743.     if (sp)
  744.         printf("\r  AVISO: ¡Valor de GAP alterado con opción /G!\n");
  745.       else
  746.         printf("\r  WARNING: GAP value modified with /G switch!\n");
  747.  
  748.   if (cmd->HD==3)
  749.     if (sp)
  750.         printf("\r  AVISO: ¡Parámetro indocumentado /D1 activo!\n");
  751.       else
  752.         printf("\r  WARNING: Undocumented /D1 switch activated!\n");
  753.  
  754.   if (cmd->MarcaPoco)
  755.     if (sp)
  756.         printf("\r  AVISO: ¡Parámetro indocumentado /W activo!\n");
  757.       else
  758.         printf("\r  WARNING: Undocumented /W switch activated!\n");
  759.  
  760.   if ((cmd->X!=-1) || (cmd->Y!=-1))
  761.     if (sp)
  762.         printf("\r  AVISO: ¡Parámetro indocumentado /X ó /Y activo!\n");
  763.       else
  764.         printf("\r  WARNING: Undocumented /X or /Y switch activated!\n");
  765.  
  766.   if (sp)
  767.       printf("\r  Formateo de disquete ");
  768.     else
  769.       printf("\r  Formatting ");
  770.  
  771.   switch (TipoDrive (cmd->Unidad)) {
  772.     case 2:  printf("%s", cmd->HD==1?"5¼-1.2M":"5¼-360K");  break;
  773.     case 4:  printf("%s", cmd->HD==1?"3½-1.44M":"3½-720K"); break;
  774.     default: if (cmd->ED) printf("3½-2.88M");
  775.                else printf("%s", cmd->HD==1?"3½-1.44M":"3½-720K");
  776.     }
  777.  
  778.   if (sp)
  779.       printf(" en %c: con %dK        \n",
  780.              cmd->UnidadLogica+'A', sector0->NumSect>>1);
  781.     else
  782.       printf(" diskette on %c: with %dK        \n",
  783.              cmd->UnidadLogica+'A', sector0->NumSect>>1);
  784.  
  785.   for (i=0; i<MAXFAT; i++) fat[i]=0;  /* poner a 0 la futura FAT */
  786.   fat[0]=sector0->MediaId; fat[1]=fat[2]=0xFF;
  787.  
  788.   for (i=0; i < ((unsigned long) MAXSECT <<9); i++) buffer[i]=0;
  789.  
  790.   cilindros=sector0->NumSect/(sector0->SectPista*sector0->Caras);
  791.   spista=sector0->SectPista; *bytes_def=0L;
  792.   fases=1L*cilindros*sector0->Caras*(1+(1-cmd->NoVerify)+sector0->FlagWr);
  793.   fase=0L;
  794.  
  795.   tini=*cbios;
  796.   for (cilindro=0; cilindro < cilindros ; cilindro++) {
  797.     for (cabezal=0; cabezal<sector0->Caras; cabezal++) {
  798.       for (intento=0; intento<3; intento++) {
  799.         if (sp)
  800.             printf("\r  Cilindro %2d - Cara %d  [F-]  %3lu%%",
  801.                    cilindro, cabezal, fase*100/fases);
  802.           else
  803.             printf("\r  Cylinder %2d - Side %d  [F-]  %3lu%%",
  804.                    cilindro, cabezal, fase*100/fases);
  805.         if (error) biosdsk (0, cmd->Unidad, 0, 0, 0, 0, NULL);
  806.         t=0; while (bioskey(1)) t=bioskey(0);
  807.         if ((t & 0xFF)==0x1B) { error=1; goto AbortFormat; }
  808.           else if (((t==0x1000) || (cmd->Rapido)) && (cilindro>1))
  809.             goto FinFormat;
  810.         error=biosdsk (5, cmd->Unidad, cabezal,
  811.                        cilindro, 0, 0x7F, (unsigned char far *) sector0);
  812.         if (sector0->FlagWr==1) if (!error && (cilindro | cabezal)) {
  813.           printf ("\b\b\b\b\b\b\b\b\bI-]  %3lu%%",(fase+1)*100/fases);
  814.           error=biosdsk (3, cmd->Unidad, cabezal | 0x80,
  815.                          cilindro, 1, spista, buffer);
  816.           }
  817.         if (!error&&(!cmd->NoVerify||(cmd->NoVerify && cilindro<2))) {
  818.           printf ("\b\b\b\b\b\b\b\b\b-V]  %3lu%%",
  819.                  (fase+1+sector0->FlagWr)*100/fases);
  820.           error=biosdsk (2, cmd->Unidad, cabezal,
  821.                          cilindro, 1, spista, buffer);
  822.           }
  823.         if (!error) break;
  824.         }
  825.       if (error)
  826.         if ((error==128) || (error==3) || (error==6))
  827.             goto AbortFormat;   /* error fatal */
  828.           else
  829.             if (!MarcaFat(cmd->Unidad, cmd->MarcaPoco, sector0,
  830.                 cilindro, cabezal, fat, buffer, bytes_def))
  831.               goto AbortFormat; /* error en áreas del sistema */
  832.       fase+=(1+(1-cmd->NoVerify)+sector0->FlagWr);
  833.     }
  834.     hist[cilindro]=*cbios;
  835.     tiempo=(*cbios-tini)*10/182;
  836.     printf("                [%2lu:%02lu ]", tiempo/60, tiempo % 60);
  837.     if (cilindro>5) {
  838.       rest=(*cbios-hist[cilindro-5])*(cilindros-cilindro)*10/910;
  839.       printf("\b+%2lu:%02lu =%2lu:%02lu ]", rest/60, rest % 60,
  840.              (tiempo+rest)/60, (tiempo+rest) % 60);
  841.       }
  842.     if (!error && (cilindro>79)) /* verificar siempre aquí */ {
  843.       error=biosdsk (2, cmd->Unidad, 0, cilindro-1, 1, spista, buffer);
  844.       if (error) { /* no soportadas tantas pistas */
  845.         cilindros=cilindro; cilindro-=2;
  846.         biosdsk (0, cmd->Unidad, 0, 0, 0, 0, NULL);
  847.         }
  848.       }
  849.   }
  850.  
  851.   if (cmd->Pistas!=cilindros) { /* no soportadas tantas pistas */
  852.     t=cmd->Pistas;
  853.     cmd->Pistas=cilindros;          /* nº pistas correcto */
  854.     CrearSector0 (sector0, *cmd);   /* sector de arranque final */
  855.     cmd->Pistas=t;                  /* restaurar parámetro */
  856.     }
  857.  
  858.   FinFormat: error=InicializaDisco(cmd->Unidad, sector0, fat, buffer);
  859.  
  860.   AbortFormat: printf("\r"); for (i=0; i<79; i++) printf(" ");
  861.  
  862.   *segundos=(*cbios-tini)*10/182;
  863.  
  864.   return (error);
  865. }
  866.  
  867.  
  868. void InformeDisco (s0, cmd, bd, tiempo)
  869. Boot *s0;
  870. Parametros *cmd;
  871. long bd;
  872. int tiempo;
  873. {
  874.   unsigned long st, ua, bt;
  875.   int      cilindros;
  876.   char     label[12];
  877.  
  878.   st = s0->NumSect - s0->NumFats * s0->SectFat
  879.        - s0->SectReserv - (s0->FichRaiz>>4);
  880.   ua = st / (unsigned long) s0->SectCluster;  bt = st*512L;
  881.  
  882.   cilindros=s0->NumSect/(s0->SectPista*s0->Caras);
  883.  
  884.   strncpy (label, s0->Titulo, 11); label[11]=0;
  885.  
  886.   if (sp) {
  887.       printf ("\r  Tiempo transcurrido formateando %2d:%02d\n",
  888.         tiempo/60, tiempo % 60);
  889.       printf ("  Volúmen con número de serie %04X-%04X",
  890.         (int) (s0->NumSerie >> 16), (int) s0->NumSerie);
  891.       if (strstr(label, "NO NAME    ")==NULL)
  892.           printf (" y etiqueta %11s\n", label);
  893.         else
  894.           printf("\n");
  895.       printf ("%9d ficheros permitidos en el raíz.\n",
  896.         s0->FichRaiz);
  897.       printf ("%9d unidades de asignación.\n", ua);
  898.       printf ("%9d bytes por unidad de asignación.\n",
  899.         s0->SectCluster*512);
  900.       printf ("%9lu bytes totales en el disco.\n", bt);
  901.       printf ("%9lu bytes en sectores defectuosos.\n", bd);
  902.       printf ("%9lu bytes disponibles en el disco.\n", bt-bd);
  903.       if (cilindros!=cmd->Pistas)
  904.         printf("          Aviso: formateado con %dK (esta unidad sólo"
  905.                " soporta %d pistas).\n", s0->NumSect>>1, cilindros);
  906.       }
  907.     else {
  908.       printf ("\r  Time elapsed in the process %2d:%02d\n",
  909.         tiempo/60, tiempo % 60);
  910.       printf ("  Volume serial number is %04X-%04X",
  911.         (int) (s0->NumSerie >> 16), (int) s0->NumSerie);
  912.       if (strstr(label, "NO NAME    ")==NULL)
  913.           printf (" labeled %11s\n", label);
  914.         else
  915.           printf("\n");
  916.       printf ("%9d file capacity of root directory.\n",
  917.         s0->FichRaiz);
  918.       printf ("%9d total clusters on disk.\n", ua);
  919.       printf ("%9d bytes per cluster.\n",
  920.         s0->SectCluster*512);
  921.       printf ("%9lu total bytes on disk.\n", bt);
  922.       printf ("%9lu bytes on bad sectors.\n", bd);
  923.       printf ("%9lu bytes available on disk.\n", bt-bd);
  924.       if (cilindros!=cmd->Pistas)
  925.         printf("          Note: formatted with %dK (this drive supports"
  926.                " only %d tracks).\n", s0->NumSect>>1, cilindros);
  927.       }
  928. }
  929.  
  930.  
  931. void IncrementarEtiqueta (Parametros *cmd)
  932. {
  933.   int j=10;
  934.  
  935.   while ((cmd->Volumen[j]==' ') && j) j--;
  936.  
  937.   while (j)
  938.     if ((cmd->Volumen[j] >= '0') && (cmd->Volumen[j] <= '8')) {
  939.         cmd->Volumen[j]++;
  940.         break;
  941.         }
  942.       else if (cmd->Volumen[j] == '9') {
  943.           cmd->Volumen[j]='0';
  944.           j--;
  945.           }
  946.         else break;
  947. }
  948.  
  949.  
  950. void DiagnosticoError (int codigo)
  951. {
  952.   if (sp) {
  953.       switch (codigo) {
  954.         case 1:   printf("\r  Formateo interrumpido por el usuario.");
  955.                   break;
  956.         case 2:   printf("\r  La densidad seleccionada es incorrecta.");
  957.                   break;
  958.         case 3:   printf("\r  Disquete protegido contra escritura.");
  959.                   break;
  960.         case 6:
  961.         case 128: printf("\r  Unidad no preparada (¿puerta abierta?).");
  962.                   break;
  963.         default:  printf("\r  Anomalía general: ¿densidad incorrecta?.");
  964.                   break;
  965.         }
  966.       }
  967.     else {
  968.       switch (codigo) {
  969.         case 1:   printf("\r  Format aborted by user.");
  970.                   break;
  971.         case 2:   printf("\r  Selected density is incorrect.");
  972.                   break;
  973.         case 3:   printf("\r  Diskette is write-protected.");
  974.                   break;
  975.         case 6:
  976.         case 128: printf("\r  Drive not ready (door open?).");
  977.                   break;
  978.         default:  printf("\r  General failure: incorrect density?.");
  979.                   break;
  980.         }
  981.       }
  982.   printf("                                  \n");
  983. }
  984.  
  985.  
  986. int MarcaFat (unidad, modosuave, sector0, cil, cab, fat, buffer, bytes_mal)
  987. Boot     *sector0;
  988. int      unidad, modosuave, cil, cab;
  989. unsigned char far *fat;
  990. unsigned char far *buffer;
  991. long     *bytes_mal;
  992. {
  993.   unsigned malclus, i, ini, tamsys;
  994.  
  995.   tamsys = sector0->NumFats*sector0->SectFat+(sector0->FichRaiz>>4)+1;
  996.  
  997.   for (i=1; i<=sector0->SectPista; i++) {
  998.     ini=(cil*sector0->Caras+cab)*sector0->SectPista+i-1;
  999.     if (modosuave)
  1000.         malclus=biosdsk (2, unidad, cab, cil, i, 1, buffer);
  1001.       else
  1002.         malclus=1;  /* por defecto marcar la pista entera */
  1003.     if (malclus) {
  1004.       if (ini<tamsys) break;  /* error en áreas del sistema */
  1005.       *bytes_mal+=sector0->SectCluster*512L;
  1006.       ini-=tamsys; ini=ini/sector0->SectCluster+2;
  1007.       if (ini % 2) { /* posición impar */
  1008.           fat [ini*3/2] = fat [ini*3/2] & 0x0F | 0x70;
  1009.           fat [ini*3/2+1] = 0xFF;
  1010.           }
  1011.         else {       /* posición par */
  1012.           fat [ini*3/2] = 0xF7;
  1013.           fat [ini*3/2+1] = fat [ini*3/2+1] & 0xF0 | 0x0F;
  1014.           }
  1015.       ini=0x7FFF;
  1016.       }
  1017.     }
  1018.   return (ini>=tamsys);
  1019. }
  1020.  
  1021.  
  1022. int TipoDrive (int unidad)
  1023. {
  1024.   union REGS r;
  1025.  
  1026.   r.h.ah=8; r.h.dl=unidad; int86 (0x13, &r, &r);
  1027.  
  1028.   if (r.x.flags & 1) { r.h.ah=8; r.h.dl=unidad; int86 (0x13, &r, &r);}
  1029.  
  1030.   return ((unsigned char) r.h.bl);
  1031. }
  1032.  
  1033.  
  1034. InicializaDisco (unidad, sector0, fat1, buffer)
  1035. int      unidad;
  1036. Boot     *sector0;
  1037. unsigned char far *fat1;
  1038. unsigned char far *buffer;
  1039. {
  1040.   unsigned char far *p;
  1041.   int      sectpista0=sector0->Salto[sector0->OffsetPista0],
  1042.            spraiz=sector0->SectFat*2+1,
  1043.            psr, nsr, cab, cil, error;
  1044.   Root     raiz;
  1045.   struct   time h;
  1046.   struct   date f;
  1047.  
  1048.   memset (buffer, 0, (unsigned long) MAXSECT << 9);
  1049.   memset (&raiz, 0, sizeof (raiz));
  1050.  
  1051.   if (strstr(sector0->Titulo, "NO NAME    ")==NULL) {
  1052.     strncpy (raiz.Etiqueta, sector0->Titulo, 11);
  1053.     raiz.Tipo=0x28;
  1054.     gettime (&h); getdate (&f);
  1055.     raiz.Fecha=((f.da_year-1980)<<9) | (f.da_mon<<5) | f.da_day;
  1056.     raiz.Hora=(h.ti_hour<<11) | (h.ti_min<<5) | (h.ti_sec>>1);
  1057.     }
  1058.  
  1059.   p=buffer;
  1060.     memcpy (p, sector0, 512);                /* BOOT físico */
  1061.   p+=512;
  1062.     memcpy (p, fat1, sector0->SectFat*512);  /* FAT1 (la 2 emulada) */
  1063.   p+=sector0->SectFat<<9;
  1064.     memcpy (p, sector0, 512);                /* BOOT virtual */
  1065.   if (sector0->SectPista>=15) /* HD */ {
  1066.     p+=512;
  1067.     memcpy (p, &Boot2mCode, Boot2mLong);     /* código SuperBOOT */
  1068.     }
  1069.   p=buffer+(spraiz<<9);
  1070.     memcpy (p, &raiz, sizeof(raiz));         /* 1ª entrada ROOT */
  1071.  
  1072.   biosdsk (0, unidad, 0, 0, 0, 0, NULL);
  1073.   error=biosdsk(3, unidad, 0x80, 0, 1, sectpista0, buffer);
  1074.   if (!error) {
  1075.     memset (buffer, 0, (unsigned long) MAXSECT << 9);   /* ROOT */
  1076.     memcpy (buffer, &raiz, sizeof(raiz));
  1077.     psr = (spraiz % sector0->SectPista) + 1;
  1078.     nsr = sector0->SectPista - psr + 1;
  1079.     cil = 0; cab = spraiz/sector0->SectPista;
  1080.     error=biosdsk(3, unidad, cab, cil, psr, nsr, buffer);
  1081.     if (nsr < sector0->FichRaiz) {
  1082.       memset (buffer, 0, sizeof(raiz)); cab++; if (cab>1) { cab=0; cil++;}
  1083.       error=biosdsk(3, unidad, cab, cil, 1, sector0->SectPista, buffer);
  1084.       }
  1085.     }
  1086.   return (error);
  1087. }
  1088.  
  1089.  
  1090. void SonidoSube()
  1091. {
  1092.   int frec=50;
  1093.  
  1094.   SonidoOn();
  1095.   while (frec<5000) {
  1096.     Sonido (frec); PicoRetardo(); Sonido (frec+1000); PicoRetardo();
  1097.     frec+=10;
  1098.   }
  1099.   SonidoOff();
  1100. }
  1101.  
  1102.  
  1103. void SonidoBaja()
  1104. {
  1105.   int frec=6000;
  1106.  
  1107.   SonidoOn();
  1108.   while (frec>1050) {
  1109.     Sonido (frec); PicoRetardo(); Sonido (frec-1000); PicoRetardo();
  1110.     frec-=10;
  1111.   }
  1112.   SonidoOff();
  1113. }
  1114.  
  1115.  
  1116. void SonidoError()
  1117. {
  1118.   int frec1=50, frec2=6000;
  1119.  
  1120.   SonidoOn();
  1121.   while (frec1<5000) {
  1122.     Sonido (frec1); PicoRetardo(); Sonido (frec1+1000); PicoRetardo();
  1123.     Sonido (frec2); PicoRetardo(); Sonido (frec2-1000); PicoRetardo();
  1124.     frec1+=10; frec2-=10;
  1125.   }
  1126.   SonidoOff();
  1127. }
  1128.  
  1129.  
  1130. void SonidoOn()
  1131. {
  1132.   disable(); outportb (0x61, inportb (0x61) | 3); enable();
  1133.   outportb (0x43, 182);  /* preparar canal 2 */
  1134. }
  1135.  
  1136.  
  1137. void SonidoOff()
  1138. {
  1139.   disable(); outportb (0x61, inportb (0x61) & 0xFC); enable();
  1140. }
  1141.  
  1142.  
  1143. void Sonido (int frecuencia)
  1144. {
  1145.   unsigned periodo;
  1146.  
  1147.   periodo=1193180L/frecuencia;
  1148.   outportb (0x42, periodo & 0xFF);  outportb (0x42, periodo >> 8);
  1149. }
  1150.  
  1151.  
  1152. int EsperarCambioDisco (int disquetera, int flash)
  1153. {
  1154.   int    i, unidad, tec;
  1155.   long   hora, iter;
  1156.  
  1157.   unidad=disquetera;
  1158.   if (FdswapOn()) unidad^=1;  /* unidades intercambiadas por FDSWAP */
  1159.  
  1160.   while (kbhit()) (void) getch();         /* limpiar buffer teclado */
  1161.  
  1162.   pokeb(0x40,0x3F, peekb(0x40, 0x3F) & 0xF0); /* "motores apagados" */
  1163.  
  1164.   do {                           /* esperar que retiren el disquete */
  1165.     hora=*cbios+5;
  1166.     while (*cbios<hora);
  1167.     outportb (FD_DOR, (1<<(unidad+4)) | unidad | 4+8);  /* encender */
  1168.     i=inportb (FD_DIR);                     /* leer línea de cambio */
  1169.     outportb (FD_DOR, unidad | 4+8);                /* apagar motor */
  1170.     i = (i >> 7) | kbhit();
  1171.   } while (!i);
  1172.  
  1173.   if (flash)                 /* intento de bajar la línea de cambio */
  1174.       iter=2000000000L;
  1175.     else
  1176.       iter=8L;
  1177.   while (i && !kbhit()) {                     /* y parpadeo del LED */
  1178.     hora=*cbios+6;
  1179.     pokeb (0x40, 0x40, 0xFF);       /* para BIOS pelmas no estándar */
  1180.     outportb (FD_DOR,(1<<(unidad+4)) | unidad | 4+8);   /* encender */
  1181.     pokeb(0x40,0x3F, peekb(0x40, 0x3F) | (1<<unidad));
  1182.     posicionar (unidad, 1);
  1183.     while ((*cbios<hora) && !kbhit());
  1184.     posicionar (unidad, 0);
  1185.     i = inportb (FD_DIR) >> 7;              /* leer línea de cambio */
  1186.     if (i && !iter) {
  1187.       outportb (FD_DOR, unidad | 4+8);              /* apagar motor */
  1188.       pokeb(0x40,0x3F, peekb(0x40, 0x3F) & 0xF0);
  1189.       hora+=12;
  1190.       while ((*cbios<hora) && !kbhit());
  1191.       }
  1192.     if (iter) iter--;
  1193.     }
  1194.  
  1195.   /* simular cambio de disco para anular efecto de bajada de línea */
  1196.  
  1197.   biosdsk (5, disquetera, 0, 0, 0xFF, 0x7F, NULL); /* función de 2M */
  1198.  
  1199.   /* 3 segundos para detención del motor */
  1200.  
  1201.   pokeb (0x40, 0x40, 54);
  1202.   if (kbhit()) tec=getch(); else tec=13;  if (!tec) tec=getch()<<8;
  1203.   return ((tec & 0xFF)==13);
  1204. }
  1205.  
  1206.  
  1207. void posicionar (int unidad, int cilindro)         /* mover cabezal */
  1208. {
  1209.   outfdc (0xF);          /* comando 'Seek' */
  1210.   outfdc (unidad);       /* byte 1 de dicho comando */
  1211.   outfdc (cilindro);
  1212.  
  1213.   EsperarInt();          /* esperar interrupción */
  1214.  
  1215.   outfdc (8);            /* comando 'leer estado de interrupciones' */
  1216.  
  1217.   (void) infdc();  (void) infdc();
  1218. }
  1219.  
  1220.  
  1221. void outfdc (unsigned char dato)     /* enviar byte al FDC */
  1222. {                                    /* no esperando más de 440 ms */
  1223.   int  i=0, rd;
  1224.   long t;
  1225.  
  1226.   do {
  1227.     i++; t=*cbios;
  1228.     while ((t==*cbios) && ((rd=inportb(FD_STATUS)>>7)==0));
  1229.   } while ((i<8) && !rd);
  1230.  
  1231.   if (rd) outportb (FD_DATA, dato);
  1232. }
  1233.  
  1234.  
  1235. int infdc()          /* leer byte del FDC */
  1236. {                    /* no esperando más de 440 ms */
  1237.   int  i=0, rd;
  1238.   long t;
  1239.  
  1240.   do {
  1241.     i++; t=*cbios;
  1242.     while ((t==*cbios) && ((rd=inportb(FD_STATUS)>>7)==0));
  1243.   } while ((i<8) && !rd);
  1244.  
  1245.   if (rd) return (inportb (FD_DATA)); else return (-1);  /* fallo */
  1246. }
  1247.  
  1248.  
  1249. void EsperarInt()       /* Esperar interrupción no más de 2 seg. */
  1250. {
  1251.   int  i=0;
  1252.   long t;
  1253.  
  1254.   do {
  1255.     i++; t=*cbios;
  1256.     while ((t==*cbios) && !(*irq6 & 0x80));
  1257.   } while ((i<37) && !(*irq6 & 0x80));
  1258.  
  1259.   *irq6=*irq6 & 0x7F;
  1260. }
  1261.  
  1262.  
  1263. void CardWare (char *nfich, int discos)
  1264. {
  1265.   int            fich, aviso=0, lcad;
  1266.   unsigned int   i, contador;
  1267.   struct   ftime fechahora;
  1268.   unsigned char  chk[10],
  1269.                  cmp[]="Cnt",
  1270.                  num[]="00000",
  1271.                  cw[]="000";
  1272.  
  1273.   lcad=strlen(cmp)+2;
  1274.   if ((fich=open(nfich, O_BINARY | O_RDWR))==-1) return;
  1275.   if (getftime (fich, &fechahora)==-1)   { close(fich); return; }
  1276.   if (lseek (fich, -lcad, SEEK_END)==-1) { close(fich); return; }
  1277.   if (read (fich, chk, lcad)==-1)        { close(fich); return; }
  1278.   chk[lcad-2]=0;
  1279.   if (strcmp(chk, cmp)) /* contador no inicializado */ {
  1280.     write (fich, cmp, strlen(cmp));
  1281.     contador=0; write (fich, &contador, sizeof(unsigned int));
  1282.     if (discos) discos--;
  1283.     }
  1284.   if (lseek (fich, -2L, SEEK_END)==-1)   { close(fich); return; }
  1285.   if (read (fich, &contador, 2)==-1)     { close(fich); return; }
  1286.  
  1287.   for (i=contador+1; i<=contador+discos; i++)
  1288.     if (((i % CARDWARE)==0) && (i>99)) aviso++;  /* pasada frontera */
  1289.   contador+=discos;
  1290.  
  1291.   if (lseek (fich, -2L, SEEK_END)==-1)  { close(fich); return; }
  1292.   if (write (fich, &contador, 2)==-1)   { close(fich); return; }
  1293.   flushall();
  1294.   setftime (fich, &fechahora);
  1295.   close (fich);
  1296.  
  1297.   num[0]=contador / 10000 + '0'; contador%=10000;
  1298.   num[1]=contador / 1000  + '0'; contador%=1000;
  1299.   num[2]=contador / 100   + '0'; contador%=100;
  1300.   num[3]=contador / 10    + '0'; contador%=10;
  1301.   num[4]=contador+'0';
  1302.  
  1303.   i=CARDWARE;
  1304.   cw[0]=i / 100 + '0'; i%=100;
  1305.   cw[1]=i / 10  + '0'; i%=10;
  1306.   cw[2]=i+'0';
  1307.  
  1308.   if (aviso)
  1309.     if (sp) {
  1310.         clrscr();
  1311.         textcolor (LIGHTCYAN + BLINK); textbackground (BLUE);
  1312.         gotoxy (27, 5);
  1313.         cputs(" ¡¡AVISO MUY IMPORTANTE!! ");
  1314.         textcolor (LIGHTRED); textbackground (BLACK);
  1315.         gotoxy (15,7);  cputs ("Esta copia de 2MF ya ha formateado ");
  1316.                         textcolor (YELLOW);
  1317.                         if (num[0]!='0') cputs (num);
  1318.                         else if (num[1]!='0') cputs (&num[1]);
  1319.                         else cputs (&num[2]);
  1320.                         textcolor (LIGHTRED);
  1321.                         cputs (" disquetes.");
  1322.         gotoxy (15,8);  cputs ("Recuerda que 2M es un programa  ");
  1323.                         textcolor (LIGHTGREEN); cputs ("CardWare"); textcolor (LIGHTRED);
  1324.                         cputs (".  Si aún");
  1325.         gotoxy (15,9);  cputs ("no has enviado tu  ");
  1326.                         textcolor (LIGHTMAGENTA); cputs ("tarjeta postal"); textcolor (LIGHTRED);
  1327.                         cputs ("  al  autor,  no");
  1328.         gotoxy (15,10); cputs ("deberías continuar utilizando estos discos.");
  1329.         gotoxy (15,12); cputs ("Si ya la has enviado,  estoy ");
  1330.                         textcolor (LIGHTCYAN); cputs ("muy contento"); textcolor (LIGHTRED);
  1331.                         cputs (" contigo");
  1332.         gotoxy (15,13); cputs ("y dentro de otros ");
  1333.                         cputs (cw); cputs(" volveré a felicitarte.");
  1334.         gotoxy (15,15); textcolor (LIGHTGREEN); cputs ("¡Suerte!");
  1335.         textcolor (WHITE);
  1336.         gotoxy (1,17);
  1337.         }
  1338.       else {
  1339.         clrscr();
  1340.         textcolor (LIGHTCYAN + BLINK); textbackground (BLUE);
  1341.         gotoxy (27, 5);
  1342.         cputs(" ¡¡VERY IMPORTANT NOTICE!! ");
  1343.         textcolor (LIGHTRED); textbackground (BLACK);
  1344.         gotoxy (15,7);  cputs ("This 2MF program has already formatted ");
  1345.                         textcolor (YELLOW);
  1346.                         if (num[0]!='0') cputs (num);
  1347.                         else if (num[1]!='0') cputs (&num[1]);
  1348.                         else cputs (&num[2]);
  1349.                         textcolor (LIGHTRED);
  1350.                         cputs (" disks.");
  1351.         gotoxy (15,8);  cputs ("Remember that 2M is a  ");
  1352.                         textcolor (LIGHTGREEN); cputs ("CardWare"); textcolor (LIGHTRED);
  1353.                         cputs ("  program.  If you");
  1354.         gotoxy (15,9);  cputs ("haven't send still your  ");
  1355.                         textcolor (LIGHTMAGENTA); cputs ("postcard"); textcolor (LIGHTRED);
  1356.                         cputs ("  to the author,");
  1357.         gotoxy (15,10); cputs ("you musn't continue on using this diskettes.");
  1358.         gotoxy (15,12); cputs ("If you have send it yet,  I'm ");
  1359.                         textcolor (LIGHTCYAN); cputs ("very happy"); textcolor (LIGHTRED);
  1360.                         cputs (" with you");
  1361.         gotoxy (15,13); cputs ("and within next "); cputs (cw); cputs(" ones I will thank you again.");
  1362.         gotoxy (15,15); textcolor (LIGHTGREEN); cputs ("Good luck!");
  1363.         textcolor (WHITE);
  1364.         gotoxy (1,17);
  1365.        }
  1366. }
  1367.  
  1368.  
  1369. int HablaSp()       /* devolver 1 si mensajes en castellano */
  1370. {
  1371.   union REGS r; struct SREGS s;
  1372.   char info[64];
  1373.   int i, idioma, spl[]={54, 591, 57, 506, 56, 593, 503, 34, 63, 502,
  1374.              504, 212, 52, 505, 507, 595, 51, 80, 508, 598, 58, 3, 0};
  1375.  
  1376.   idioma=0;          /* supuesto el inglés */
  1377.  
  1378.   if (_osmajor>=3) {
  1379.     r.x.ax=0x3800; s.ds=FP_SEG(info); r.x.dx=FP_OFF(info);
  1380.     intdosx (&r, &r, &s);
  1381.     i=0; while (spl[i++]) if (spl[i-1]==r.x.bx) idioma=1;
  1382.     }
  1383.  
  1384.   return (idioma);
  1385. }
  1386.